package xmltree

import (
	
	

	

	
	
	
)

//ParseOptions is a set of methods and function pointers that alter
//the way the XML decoder works and the Node types that are created.
//Options that are not set will default to what is set in internal/defoverride.go
type ParseOptions struct {
	Strict  bool
	XMLRoot func() xmlbuilder.XMLBuilder
}

//DirectiveParser is an optional interface extended from XMLBuilder that handles
//XML directives.
type DirectiveParser interface {
	xmlbuilder.XMLBuilder
	Directive(xml.Directive, *xml.Decoder)
}

//ParseSettings is a function for setting the ParseOptions you want when
//parsing an XML tree.
type ParseSettings func(s *ParseOptions)

//MustParseXML is like ParseXML, but panics instead of returning an error.
func ( io.Reader,  ...ParseSettings) tree.Node {
	,  := ParseXML(, ...)

	if  != nil {
		panic()
	}

	return 
}

//ParseXML creates an XMLTree structure from an io.Reader.
func ( io.Reader,  ...ParseSettings) (tree.Node, error) {
	 := ParseOptions{
		Strict:  true,
		XMLRoot: xmlele.Root,
	}
	for ,  := range  {
		(&)
	}

	 := xml.NewDecoder()
	.CharsetReader = charset.NewReaderLabel
	.Strict = .Strict

	 := 1
	 := .XMLRoot()

	,  := .Token()

	if  != nil {
		return nil, 
	}

	if ,  := .(xml.ProcInst);  && .Target == "xml" {
		,  = .Token()
	}

	 := xmlbuilder.BuilderOpts{
		Dec: ,
	}

	for  == nil {
		switch xt := .(type) {
		case xml.StartElement:
			setEle(&, , , &)
			 = .CreateNode(&)
		case xml.CharData:
			setNode(&, , , tree.NtChd, &)
			 = .CreateNode(&)
		case xml.Comment:
			setNode(&, , , tree.NtComm, &)
			 = .CreateNode(&)
		case xml.ProcInst:
			setNode(&, , , tree.NtPi, &)
			 = .CreateNode(&)
		case xml.EndElement:
			 = .EndElem()
		case xml.Directive:
			if ,  := .(DirectiveParser);  {
				.Directive(.Copy(), )
			}
		}

		,  = .Token()
	}

	if  == io.EOF {
		 = nil
	}

	return , 
}

func setEle( *xmlbuilder.BuilderOpts,  xmlbuilder.XMLBuilder,  xml.StartElement,  *int) {
	.NodePos = *
	.Tok = 
	.Attrs = .Attrs[0:0:cap(.Attrs)]
	.NS = make(map[xml.Name]string)
	.NodeType = tree.NtElem

	for  := range .Attr {
		 := .Attr[].Name
		 := .Attr[].Value

		if (.Local == "xmlns" && .Space == "") || .Space == "xmlns" {
			.NS[] = 
		} else {
			.Attrs = append(.Attrs, &.Attr[])
		}
	}

	if ,  := .(tree.NSElem);  {
		 := make(map[xml.Name]string)

		for ,  := range tree.BuildNS() {
			[.Name] = .Value
		}

		for ,  := range .NS {
			[] = 
		}

		if [xml.Name{Local: "xmlns"}] == "" {
			delete(, xml.Name{Local: "xmlns"})
		}

		for ,  := range  {
			.NS[] = 
		}

		if .GetNodeType() == tree.NtRoot {
			.NS[xml.Name{Space: "xmlns", Local: "xml"}] = tree.XMLSpace
		}
	}

	.AttrStartPos = len(.NS) + len(.Attrs) + *
	* = .AttrStartPos + 1
}

func setNode( *xmlbuilder.BuilderOpts,  xmlbuilder.XMLBuilder,  xml.Token,  tree.NodeType,  *int) {
	.Tok = xml.CopyToken()
	.NodeType = 
	.NodePos = *
	*++
}